﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Xsl;
using System.Reflection;
using System.IO;
using System.CodeDom.Compiler;
using System.Diagnostics;

namespace GenericLibrary.Xml.Xsl {

    //public interface IXslTransformContext<T> where T : IXslTransformContext<T>, new() {

    //    XsltSettings GetSettings();
    //    XmlResolver GetResolver();
    //    XsltArgumentList GetArgumentList();
    //}

    class XslTransformWrapper<TContext> : MarshalByRefObject where TContext :class, IXslTransformContext<TContext>, new() {

        private XslCompiledTransform _xslt;
        private TContext _context;

        public AppDomain GetWorkingDomain() {
            return AppDomain.CurrentDomain;
        }

        public TempFileCollection TemporaryFiles {
            get {
                return this._xslt.TemporaryFiles;
            }
        }

        public void Load( Stream xslt ) {
            try {
                using( XmlReader reader = XmlReader.Create( xslt ) ) {
                    this._xslt.Load( reader, this._context.GetSettings(), this._context.GetResolver() );
                    reader.Close();
                }
                this._xslt.TemporaryFiles.KeepFiles = false;
            } catch( Exception ) {
                Debug.Assert( false );
                throw;
            }
        }

        public void Transform( Stream input, Stream output ) {
            try {
                using( XmlReader reader = XmlReader.Create( input ) ) {
                    this._xslt.Transform( reader, this._context.GetArgumentList(), output );
                    reader.Close();
                }
            } catch( Exception ) {
                Debug.Assert( false );
                throw;
            }
        }

        public XslTransformWrapper() {
            this._xslt = new XslCompiledTransform( true );
            this._context = new TContext();
        }

    }

    //public class DefaultXslTransformContext : IXslTransformContext<DefaultXslTransformContext> {

    //    public virtual XsltSettings GetSettings() {
    //        return new XsltSettings( false, true );
    //    }

    //    public virtual XmlResolver GetResolver() {
    //        return null;
    //    }

    //    public virtual XsltArgumentList GetArgumentList() {
    //        try {
    //            XsltArgumentList argumentList = new XsltArgumentList();
    //            XsltExtension extension = new XsltExtension();
    //            argumentList.AddExtensionObject( extension.NamespaceUri, extension );
    //            return argumentList;
    //        } catch( Exception ) {
    //            Debug.Assert( false );
    //            throw;
    //        }
    //    }
    //}

    //public abstract class XslTransformDbContext<T> : DefaultXslTransformContext, IXslTransformContext<T> where T : XslTransformDbContext<T>, new() {

    //    protected abstract string GetDbProviderName();
    //    protected abstract string GetDbConnectionString();

    //    public override XsltArgumentList GetArgumentList() {
    //        try {
    //            XsltArgumentList argumentList = base.GetArgumentList();
    //            XsltDbExtension dbExtension = new XsltDbExtension( this.GetDbProviderName(), this.GetDbConnectionString() );
    //            argumentList.AddExtensionObject( dbExtension.NamespaceUri, dbExtension );
    //            return argumentList;
    //        } catch( Exception ) {
    //            Debug.Assert( false );
    //            throw;
    //        }
    //    }
    //}

    public class XslTransform<TContext> : IDisposable where TContext :class, IXslTransformContext<TContext>, new() {

        private XslTransformWrapper<TContext> _wrapper;

        public XslTransform( Stream xslt ) {
            try {
                AppDomainSetup ads = new AppDomainSetup();
                ads.ApplicationBase = System.Environment.CurrentDirectory;
                ads.DisallowBindingRedirects = false;
                ads.DisallowCodeDownload = true;
                ads.ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
                AppDomain workingDomain = AppDomain.CreateDomain( "WorkingDomain", null, ads );
                this._wrapper = workingDomain.CreateInstanceAndUnwrap( typeof( XslTransformWrapper<TContext> ).Assembly.FullName, typeof( XslTransformWrapper<TContext> ).FullName ) as XslTransformWrapper<TContext>;
                this._wrapper.Load( xslt );
            } catch( Exception ) {
                Debug.Assert( false );
                throw;
            }
        }

        public void Dispose() {
            try {
                using( TempFileCollection tempFiles = this._wrapper.TemporaryFiles ) {
                    AppDomain.Unload( this._wrapper.GetWorkingDomain() );
                    tempFiles.Delete();
                }
            } catch( Exception ) {
                Debug.Assert( false );
                throw;
            }
        }

        public void Transform( Stream input, Stream output ) {
            try {
                this._wrapper.Transform( input, output );
            } catch( Exception ) {
                Debug.Assert( false );
                throw;
            }
        }


    }




}
